<?php
/**
* @author Jelle Heemskerk <riverburn@gmail.com>, Niek Saarberg <n.saarberg@gmail.com>
* @version 0.0.4
* @package Router
* @date March 12, 2009
*
* Todo:
* - 
*
* Changes:
* 0.0.4
* - Niek S. Added check in ::delegate() to see check if the requested url is an file, if it is, parse file
*   Added ::getMimeType(), this function gives an mime-type by extension
* 0.0.3
* - Niek S. Add function delegate() use of PHP in js files
* 0.0.2
* - Niek S. Added the funtion setRouteModus() and ROUTER_MODE_***** constants
*   Also added the switch statement in getRoute()
* 0.0.1
* - Class created and added created base functionality
*/


/**
 * Define router vars
 */
define('ROUTER_MODE_NORMAL', 0);
define('ROUTER_MODE_HTML', 1);
define('ROUTER_MODE_MOD_REWRITE_OFF', 10);


class Router {

	public $registry;
    public $route;
    
    /**
     * Modus of the url, default 0
     * 
     * 0: /baseUrl/controller/[action/]params
	 * 1: /baseUrl/controller/action-param1-param2.html
     */
    public $urlModus = ROUTER_MODE_NORMAL;
	
	/**
	 * Holds the controller path
	 * 
	 * @param string $controllerPath
	 */
    public $controllerPath;
	
	/**
	 * Class contructor
	 * 
	 * @param object reference to registry
	 * @return void
	 */
	public function __construct(&$registry) {

		$this->registry = $registry;
	}
	
	/**
	 * How the url will be progressed
	 */
	public function setRouteModus($int) {
		
		$this->urlModus = $int;
	}
	
	/**
	 * Finds the controller and [action if is set]
	 * Also lists the additional params
	 */
    public function getRoute( &$route ) {
		
		/**
		 * Changes the url for further progress
		 */
		switch ($this->urlModus) {
			
			case ROUTER_MODE_NORMAL: 
				break;
			
			case ROUTER_MODE_HTML:
				
				$route = str_replace('.html', '', $route);
				$route = str_replace('-', '/', $route);
				break;
		}
		
		/**
		 * Separate the url
		 */
		$package 	= explode('/', $route);
		
		/**
		 * Get controller path
		 */
		$cmd_path = $this->controllerPath;
		$view_path = '';
			
		/**
		 * loop trough the url to find the correct directory and controller
		 */
		foreach($package as $part) {
			
			$fullpath = $cmd_path . $part;
			
			if(is_dir($fullpath . DIRSEP)) {
				
				$cmd_path .= $part . DIRSEP;
				$view_path .= $part . DIRSEP;
				$controller = 'index';
				array_shift($package);
				
				continue;
			}
			
			// Controller found
			if(is_readable($fullpath . 'Controller.php')) {
				
				$controllerFile = $fullpath . 'Controller.php';
				$controller = $part;
				array_shift($package);
				
				break;
			}
		}
		
		/**
		 * If controller isn't found, set it to index
		 * This must be on or off.
		 */
		if(!isset($controller)) {
			
			$controller = 'index';
		}
		
		/**
		 * Just a guess but first arg left would be the action
		 */
		$action 	= array_shift($package);
		
		$action 	= (empty($action)) ? 'index' : $action;
		$controller	= (isset($controller) && empty($controller)) ? 'index' : $controller;
		
		/**
		 * Controller file
		 */
		$file 		= $cmd_path . $controller . 'Controller.php';
		
		/**
		 * Set vars we found
		 */
		$this->route = array(
					'controller' => $controller,
					'action' => $action,
					'parameter' => $package,
					'file' => $file,
					'view_path' => $view_path
			);
    }
    
    /**
     * Set controller path
     * 
     * @param string $path
     * @return void
     */
    public function setControllerPath($path) {

        $path  = rtrim($path, '/\\');
		
        $path .= DIRSEP;

        if (!is_dir($path)) {
            
            throw new Exception('Invalid controller path: `' . $path . '`.');
        }

        $this->controllerPath = $path;
    }
    
    /**
     * Trigger your script
     *
     * @return void
     */
    public function delegate() {
		
		// Get requested uri
		$route = (!isset($_GET['route'])) ? 'index' : trim($_GET['route'], '/\\');
		
		// Parse a text file, js or css file for example
		if( $this->parseTextFile( &$route ) ) {
			
			return true;
		}
		
		$this->getRoute( &$route );

        if (!is_readable($this->route['file'])) {

            throw new Exception('Cannot load controller: `' . $this->route['controller'] . '`.');
        }

        include_once $this->route['file'];

        $class = $this->route['controller'] . 'Controller';
        
        $controller = new $class($this->registry);
        
        if (!method_exists($controller, $this->route['action'] . 'Action')) {
        	
        	/**
        	 * Changed Feb 12, 09
        	 *
        	 * No more error function, instead we use the index and see the action as an parameter
        	 * Cause the index action must exists!
        	 */
        	
        	if(is_array($this->route['parameter'])) {
        	
        		$this->route['parameter'] = array_merge(array($this->route['action']), $this->route['parameter']);
        	} else {
        		
				$this->route['parameter'][] = $this->route['action'];
        	}
        	
        	$this->route['action'] = 'index';
        }
        
        $action = $this->route['action'] . 'Action';
		
		/**
		 * Trigger the controller
		 */
		 
		 
        $controller->$action();
    }
	
	/**
	 * Get mime-type of a file, by extension
	 *
	 * Mime types from: http://www.w3schools.com/media/media_mimeref.asp
	 *
	 * @param string $filename
	 * @return string mimetype
	 */
	private function getMimeType ( $ext ) {
		
		switch( $ext ) {
			
			// Plain text files
			case 'css':
				$mimetype = 'text/css';
				break;
			
			case 'js':
				$mimetype = 'text/javascript';
				break;
			/*
			// Images
			case 'jpe':
			case 'jpeg':
			case 'jpg':
				$mimetype = 'image/jpeg';
				break;
			
			case 'gif':
				$mimetype = 'image/gif';
				break;
			
			case 'png':
				$mimetype = 'image/png';
				break;*/
			
			// No mime type found
			// For now, use this to check if a file isn't found
			default:
				log::write( 'extension uknown `' . $ext . '`, add to router.php', $this, 'getMimeType()' );
				$mimetype = false;
				break;
		}
		
		return $mimetype;
	}
	
	/**
	 *
	 */
	private function parseTextFile ( $route ) {
		
		/**
		 * Check if we have to parse the file
		 */
		if( is_file( SITE_PATH . $route ) == true ) {
			
			$ext = substr( $route, strrpos($route, '.') + 1 );
			
			$mimetype = $this->getMimeType( $ext );
			
			if( $mimetype !== false ) {
				
				$fileInfo = stat( SITE_PATH . $route );
				
				//var_dump( $fileInfo );
				
				$eTag = 'ci-' . dechex( crc32( $fileInfo['size'] . $fileInfo['mtime'] ) );
				$gmtTime = @gmstrftime("%a, %d %b %Y %T %Z", $fileInfo['mtime']);
				
				
				header('Content-Type: ' . $mimetype);
				
				if( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) && isset( $_SERVER['HTTP_IF_NONE_MATCH'] ) ) {
					// File is cached
					
					if( strpos( $_SERVER['HTTP_IF_NONE_MATCH'], $eTag ) && $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $gmtTime ) {
						// Woohoo file is cached
						header('HTTP/1.1 304 Not Modified');
						header('Cache-Control: private');
						header("Pragma: ");
						header('Expires: ');
						header('Content-Type: ');
						header('ETag: "' . $eTag . '"');
						
						exit;
					}
				}
				
				// Set cache
				header('Cache-Control: private');
				header('Pragma: ');
				header('Expires: ');
				header('Last-Modified: ' . $gmtTime);
				header('ETag: "'.$eTag.'"');
				
				$this->registry->view->setLayoutPath( dirname($route) );
				$this->registry->view->setLayout( basename($route) , '');
				
				$this->registry->view->show();
				
				return true;
			}
		}
		
		return false;
	}
}